﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using AutoMapper;
using Core;
using IglooCoder.Commons.WcfNhibernate;
using Infrastucture;
using WcfService1.DTO;
using Omu.ValueInjecter;

namespace WcfService1
{
    // NOTE: You can use the "Rename" command on the "Refactor" BtbElse to change the class name "BtbElseServices" in code, svc and config file together.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    [NHibernateContext]
    public class BtbElseServices : IBtbElseServices
    {
        public readonly BtbElseRepository BtbElseRepository;
        public readonly ItemRepository ItemRepository;
        public readonly InventoryRepository _InventoryRepository;
        public readonly MutasiStokRepository _MutasiRepository;
        public readonly InventoryWarehouseRepository _iwRepository;
        public readonly WcfSessionStorage session;
        public PurchaseOrderRepository PORepository;
        private readonly JurnalRepository _jurnalRepository ;
        private readonly HppRepository _hppRepository;

        public BtbElseServices()
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
            session = new WcfSessionStorage();
            
            BtbElseRepository = new BtbElseRepository(session);
            ItemRepository = new ItemRepository(session);
            _InventoryRepository = new InventoryRepository(session);
            _MutasiRepository = new MutasiStokRepository(session);
            PORepository = new PurchaseOrderRepository(session);
            _iwRepository = new InventoryWarehouseRepository(session);
            _jurnalRepository = new JurnalRepository(session);
            _hppRepository = new HppRepository(session);
        }

      

        public BtbElseServices(WcfSessionStorage sessionStorage)
        {
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
            session = sessionStorage;
            BtbElseRepository = new BtbElseRepository(session);
            ItemRepository = new ItemRepository(session);
            _InventoryRepository = new InventoryRepository(session);
            _MutasiRepository = new MutasiStokRepository(session);
            PORepository = new PurchaseOrderRepository(session);
            _iwRepository = new InventoryWarehouseRepository(session);
        }
        #region IBtbElseServices Members

        public List<BtbElseDTO> GetList(int page, out long recordCount, string sortProperty = null,
                                        string sortType = "ASC")
        {
            var BtbElses = new List<BtbElse>();
            var Results = new List<BtbElseDTO>();

            if (string.IsNullOrEmpty(sortProperty))
            {
                BtbElses = BtbElseRepository.GetDataPaged(page, 30, "TglBtb", "DESC").ToList();
            }
            else
            {
                BtbElses = BtbElseRepository.GetDataPaged(page, 30, sortProperty, sortType).ToList();
            }

            recordCount = BtbElseRepository.RecordCount;

            BtbElses.ForEach(x =>
                                 {
                                     BtbElseDTO BtbElseDTO = x.ConvertToDTO<BtbElse, BtbElseDTO>();
                                     Results.Add(BtbElseDTO);
                                 }
                );

            return Results;
        }


        public bool Save(BtbElseDTO BtbElseDTO)
        {
            bool res;
            try
            {
                 BtbElseRepository.ExecuteTransactionNative(() =>
                                                               {
                                                                   BtbElse BtbElse = BtbElseRepository.GetDataOne(x => x.NoBtb == BtbElseDTO.NoBtb);
                                                                  
                                                                   if (BtbElse == null)
                                                                   {
                                                                       BtbElse = new BtbElse();
                                                                       Mapper.Map(BtbElseDTO, BtbElse);

                                                                       //Untuk New entry dari transaksi bukan dari email
                                                                       if (String.IsNullOrEmpty(BtbElse.NoBtb))
                                                                            BtbElse.NoBtb = GetLastBtbElseNo();
                                                                 

                                                                       foreach (BtbElseDetail BtbElseDetail in BtbElse.BtbDetails)
                                                                       {
                                                                           BtbElseDetail.Btb = BtbElse;
                                                                           BtbElseDetail.BtbDetailId = 0;

                                                                           //Mutasi Masuk
                                                                           var mutasiStok = new MutasiStok();
                                                                           mutasiStok.ReferenceNumber = BtbElse.NoBtb;
                                                                           mutasiStok.SerialNumber = BtbElseDetail.NoLog;
                                                                           mutasiStok.TglMutasi =
                                                                               BtbElse.TglBtb.ToDateTime();
                                                                           mutasiStok.Type = BtbElse.GetType().Name;
                                                                           mutasiStok.QtyMasuk = BtbElseDetail.QtyUnit;
                                                                           MutasiStok mutasiLast =
                                                                               _MutasiRepository.FindLastMutasi(
                                                                                   BtbElseDetail.NoLog,
                                                                                   BtbElseDetail.Warehouse.KodeWarehouse
                                                                                   ,mutasiStok.TglMutasi
                                                                                   );
                                                                           if (mutasiLast == null)
                                                                               mutasiLast = new MutasiStok();

                                                                           mutasiStok.QtySisa = mutasiLast.QtySisa +
                                                                                                mutasiStok.QtyMasuk;
                                                                           mutasiStok.SheetMasuk = BtbElseDetail.Tinggi;
                                                                           mutasiStok.SheetSisa = mutasiLast.SheetSisa +
                                                                                                  mutasiStok.SheetMasuk;
                                                                           mutasiStok.KodeWarehouse =
                                                                               BtbElseDetail.Warehouse.KodeWarehouse;
                                                                           _MutasiRepository.SaveOrUpdate(mutasiStok,BtbElseDetail.KodePallet);

                                                                           //Save or Update to Inventory
                                                                           Inventory inventory = new Inventory();
                                                                           Mapper.Map(BtbElseDetail, inventory);
                                                                           if (string.IsNullOrEmpty(inventory.Item.ItemName))
                                                                               inventory.Item =
                                                                                   ItemRepository.GetDataOne(
                                                                                       x =>
                                                                                       x.ItemId == inventory.Item.ItemId);
                                                                           if (inventory.Item == null)
                                                                               throw new Exception("Item " + inventory.Item.ItemId + " tidak ada di Master Item!");

                                                                           inventory.IsStock = true;
                                                                           inventory.UnitPrice = BtbElseDetail.Price;
                                                                           _InventoryRepository.SaveOrUpdate(inventory);
                                                                       }
                                                                       BtbElseRepository.SaveOrUpdate(BtbElse);
                                                                   }else
                                                                   {
                                                                       //Jika Status Void dan Close tdk boleh Update
                                                                       if (BtbElse.Status == (int)Status.Void || BtbElse.Status == (int)Status.Close)
                                                                           throw new Exception("Tidak bisa di Update Status sudah Close atau Void!");
                                                               

                                                                       _MutasiRepository.DeleteMutasiStok(BtbElse.NoBtb);
                                                                       BtbElseRepository.Delete(BtbElse);
                                                                    

                                                                       var NewBtb = new BtbElse();
                                                                       NewBtb.modified_date = DateTime.Now;
                                                                       NewBtb.created_date = BtbElse.created_date;
                                                                       Mapper.Map(BtbElseDTO, NewBtb);

                                                                       foreach (BtbElseDetail BtbElseDetail in NewBtb.BtbDetails)
                                                                       {
                                                                           BtbElseDetail.Btb = NewBtb;
                                                                        
                                                                           //Mutasi Masuk
                                                                           var mutasiStok = new MutasiStok();
                                                                           mutasiStok.ReferenceNumber = NewBtb.NoBtb;
                                                                           mutasiStok.SerialNumber = BtbElseDetail.NoLog;
                                                                           mutasiStok.TglMutasi = NewBtb.TglBtb.ToDateTime();
                                                                           mutasiStok.Type = NewBtb.GetType().Name;
                                                                           mutasiStok.QtyMasuk = BtbElseDetail.QtyUnit;
                                                                           MutasiStok mutasiLast =
                                                                               _MutasiRepository.FindLastMutasi(
                                                                                   BtbElseDetail.NoLog,
                                                                                   BtbElseDetail.Warehouse.KodeWarehouse
                                                                                   ,mutasiStok.TglMutasi
                                                                                   );
                                                                           if (mutasiLast == null)
                                                                               mutasiLast = new MutasiStok();

                                                                           //validasi
                                                                           if (mutasiLast.Type != null && mutasiLast.Type != BtbElse.GetType().Name && mutasiLast.TglMutasi > BtbElse.TglBtb.ToDateTime())
                                                                           {
                                                                               if (mutasiLast.Type == typeof(DeliveryOrder).Name)
                                                                                   throw new Exception("sudah terjadi Delivery Order No." + mutasiLast.ReferenceNumber  + " untuk serialnumber " + mutasiStok.SerialNumber);
                                                                               if (mutasiLast.Type == typeof(InventoryAdjustment).Name)
                                                                                   throw new Exception("sudah terjadi InventoryAdjustment No." + mutasiLast.ReferenceNumber + " untuk serialnumber " + mutasiStok.SerialNumber);
                                                                               if (mutasiLast.Type == typeof(PurchaseReturn).Name)
                                                                                   throw new Exception("sudah terjadi PurchaseReturn No." + mutasiLast.ReferenceNumber + " untuk serialnumber " + mutasiStok.SerialNumber);
                                                                               throw new Exception("Stok sudah link ke transaksi lain, tidak boleh diupdate!");
                                                                           }
                                                                              
                                                                           mutasiStok.QtySisa = mutasiLast.QtySisa +
                                                                                                mutasiStok.QtyMasuk;
                                                                           mutasiStok.SheetMasuk = BtbElseDetail.Tinggi;
                                                                           mutasiStok.SheetSisa = mutasiLast.SheetSisa +
                                                                                                  mutasiStok.SheetMasuk;
                                                                           mutasiStok.KodeWarehouse =
                                                                               BtbElseDetail.Warehouse.KodeWarehouse;
                                                                           _MutasiRepository.SaveOrUpdate(mutasiStok,BtbElseDetail.KodePallet);

                                                                           //Save or Update to Inventory
                                                                           Inventory inventory =
                                                                             _InventoryRepository.GetDataOne(
                                                                                 x =>
                                                                                 x.SerialNumber == BtbElseDetail.NoLog);
                                                                           if (inventory == null)
                                                                           {
                                                                               inventory = new Inventory();
                                                                               Mapper.Map(BtbElseDetail, inventory);
                                                                           }
                                                                           else
                                                                           {
                                                                               //Keep Panjang and Lebarnya
                                                                               var OldPanjang = inventory.Panjang;
                                                                               var OldLebar = inventory.Lebar;
                                                                               Mapper.Map(BtbElseDetail, inventory);
                                                                               inventory.Panjang = OldPanjang;
                                                                               inventory.Lebar = OldLebar;
                                                                           }

                                                                           inventory.IsStock = inventory.Item.IsStock;
                                                                           inventory.UnitPrice = BtbElseDetail.Price;
                                                                           _InventoryRepository.SaveOrUpdate(inventory);
                                                                       }

                                                                       BtbElseRepository.Session.SaveOrUpdateCopy(NewBtb);
                                                                      
                                                                   }
                                                                  
                                                               });

                res = true;
                
            }
            catch (Exception)
            {
                throw;
            }

            return res;
        }


        public bool Delete(BtbElseDTO BtbElseDTO)
        {
            bool res;
            try
            {
                BtbElse BtbElse = BtbElseRepository.GetDataOne(x => x.NoBtb == BtbElseDTO.NoBtb);

                BtbElseRepository.ExecuteTransactionNative(
                    () =>
                        {
                            foreach (BtbElseDetail BtbElseDetail in BtbElse.BtbDetails)
                            {
                                //Inventory inventory =
                                //    _InventoryRepository.GetDataOne(x => x.SerialNumber == BtbElseDetail.NoLog);
                                //_InventoryRepository.Delete(inventory);

                                var mutasiStok = _MutasiRepository.FindLastMutasi(BtbElseDetail.NoLog,
                                                                                  BtbElseDetail.Warehouse.KodeWarehouse);
                                if (mutasiStok != null && mutasiStok.ReferenceNumber != BtbElse.NoBtb)
                                    throw new Exception("Transaksi ini tidak boleh dihapus karena link ke transaksi " + mutasiStok.ReferenceNumber);

                            }

                            BtbElseRepository.Delete(BtbElse);
                            _MutasiRepository.DeleteMutasiStok(BtbElse.NoBtb);
                        }
                    );


                res = true;
            }
            catch (Exception ex)
            {               
                throw ex;
            }

            return res;
        }


        public List<BtbElseDTO> GetListByCriteria(Dictionary<String, Object> criteria, string expression, int page,
                                                  out long recordCount)
        {
            var BtbElses = new List<BtbElse>();
            var Results = new List<BtbElseDTO>();
            BtbElses = BtbElseRepository.GetDataPaged(criteria, expression, page, 30).ToList();
            recordCount = BtbElseRepository.RecordCount;
            BtbElses.ForEach(x =>
                                 {
                                     var BtbElseDTO = new BtbElseDTO();
                                     Mapper.Map(x, BtbElseDTO);
                                     Results.Add(BtbElseDTO);
                                 }
                );

            return Results;
        }


        public List<BtbElseDTO> GetAllBtbElse()
        {
            List<BtbElse> BtbElses = BtbElseRepository.FetchAll().ToList();
            var Results = new List<BtbElseDTO>();
            BtbElses.ForEach(x =>
                                 {
                                     var BtbElseDTO = new BtbElseDTO();
                                     Mapper.Map(x, BtbElseDTO);
                                     Results.Add(BtbElseDTO);
                                 }
                );

            return Results;
        }


        public BtbElseDTO GetBtbElse(String kodeBtbElse)
        {
            BtbElse BtbElse = BtbElseRepository.GetDataOne(x => x.NoBtb == kodeBtbElse);
            var BtbElseDTO = new BtbElseDTO();
            BtbElseDTO.InjectFrom<CloneInjection>(BtbElse);
            return BtbElseDTO;
        }

        public List<BtbElseDTO> GetBtbElseList(string kodeBtbElse)
        {
            List<BtbElse> BtbElses = BtbElseRepository.GetDataList(x => x.NoBtb.Contains(kodeBtbElse)).ToList();
            var Results = new List<BtbElseDTO>();
            BtbElses.ForEach(x =>
                                 {
                                     var BtbElseDTO = new BtbElseDTO();
                                     Mapper.Map(x, BtbElseDTO);
                                     Results.Add(BtbElseDTO);
                                 }
                );

            return Results;
        }

        public string GetLastBtbElseNo()
        {
            var appParamServices = new AppParamServices();
            AppParamDTO param = appParamServices.GetAppParamList("KodeBtbElse").FirstOrDefault();
           
            string res = BtbElseRepository.GetMaxNumber(param.AppParamValue);
            if (string.IsNullOrEmpty(res))
                res = param.AppParamValue;
           
            string formatSO = "0000";
            string kodeSO;
            string last = string.Empty;
            if (res.Length <= 4)
            {
                kodeSO = res;
                last = formatSO;
            }
            else
            {
                last = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[2];
                kodeSO = res.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0];
            }
            string soNum = formatSO.Substring(0, formatSO.Length - (int.Parse(last) + 1).ToString().Length) +
                           (int.Parse(last) + 1);

            return kodeSO + "/" + DateTime.Now.Year + "/" + soNum;
        }

        public Decimal GetSatuanPengali(ItemDTO itemDto)
        {
            Item item = ItemRepository.GetDataOne(x => x.ItemId == itemDto.ItemId);
            return item.Satuan.Pengali;
        }

        public bool DeleteDetail(BtbElseDetailDTO BtbElseDetailDto)
        {
            bool res;
            try
            {
                var PIDetail = BtbElseRepository.Session.Get<BtbElseDetail>(BtbElseDetailDto.BtbDetailId);
                BtbElseRepository.ExecuteTransactionNative(
                    () =>
                        {
                            Inventory inventory = _InventoryRepository.GetDataOne(x => x.SerialNumber == PIDetail.NoLog);
                            _InventoryRepository.Delete(inventory);
                            _MutasiRepository.DeleteMutasiStok(BtbElseDetailDto.NoBtb, BtbElseDetailDto.NoLog);
                            BtbElseRepository.DeleteDetail(PIDetail, BtbElseDetailDto.BtbDetailId);
                        }
                    );


                res = true;
            }
            catch (Exception)
            {
                res = false;
            }

            return res;
        }


        public bool SendEmail(BtbElseDTO BtbElseDTO, String DestinationFolder)
        {
            var mailServices = new MailServices();
            BtbElse BtbElse = BtbElseRepository.GetDataOne(x => x.NoBtb == BtbElseDTO.NoBtb);
            BtbElseDTO = Mapper.Map(BtbElse, BtbElseDTO);
            return mailServices.SendEmail(BtbElseDTO,DestinationFolder);
        }

        public void UpdateStatus(BtbElseDTO btbElseDto, Status status)
        {
            BtbElseRepository.UpdateStatus(btbElseDto.NoBtb, (int)status);
        }

        public IEnumerable<BtbElseDTO> GetListByPeriode(DateTime tglstart,DateTime tglend)
        {
            var BtbElses = new List<BtbElse>();
            BtbElses = BtbElseRepository.GetDataList(x => x.TglBtb >= tglstart && x.TglBtb <= tglend).ToList();
            var results = new List<BtbElseDTO>();

            foreach (var btbElse in BtbElses)
            {
                var btbElseDto = new BtbElseDTO();
                btbElseDto.InjectFrom(btbElse);
                results.Add(btbElseDto);
            }

            return results;
        }


        public void CreateJurnal(BtbElse btbElse)
        {
            if (btbElse.Status == 3)throw new Exception("Data Sudah di Posting!");
            //Piutang
            Jurnal jurnal = new Jurnal();
            jurnal.NoVoucher = btbElse.NoBtb;
            jurnal.TglJurnal = btbElse.TglBtb;
            jurnal.Description = btbElse.Description;
            jurnal.ReffNumber = btbElse.NoBtb;
            jurnal.TipeJurnal = typeof (BtbElse).Name;

            var hppServices = new HppServices();
            hppServices.CreateHpp(btbElse);

            foreach (var detail in btbElse.BtbDetails)
            {
                    var inventory = _InventoryRepository.GetDataOne(x => x.SerialNumber == detail.NoLog);
                    //masukkan total amount hppnya ke price untuk jurnal
                    detail.Price = detail.QtyUnit*detail.Price;
                    //Kredit Hpp
                    jurnal.JurnalDetails.Add(new JurnalDetail() { AccountNumber = inventory.Item.CoaHpp, Kredit = detail.Price, Jurnal = jurnal});
                    //Debit Inventory
                    jurnal.JurnalDetails.Add(new JurnalDetail() { AccountNumber = inventory.Item.CoaInventory, Debit = detail.Price, Jurnal = jurnal});
             }

                List<JurnalDetail> results = new List<JurnalDetail>();
                foreach (var gjd in jurnal.JurnalDetails.GroupBy(x => x.AccountNumber))
                {
                    results.Add(new JurnalDetail()
                    {
                        AccountNumber = jurnal.JurnalDetails.FirstOrDefault(x => x.AccountNumber == gjd.Key).AccountNumber,
                        Debit = jurnal.JurnalDetails.Where(x => x.AccountNumber == gjd.Key).Sum(x => x.Debit),
                        Kredit = jurnal.JurnalDetails.Where(x => x.AccountNumber == gjd.Key).Sum(x => x.Kredit),
                        Description = jurnal.JurnalDetails.FirstOrDefault(x => x.AccountNumber == gjd.Key).Description,
                        Jurnal = jurnal
                    });
                }
                jurnal.JurnalDetails = results;
          
            _jurnalRepository.SaveOrUpdate(jurnal);

        }


        public void Posting(IEnumerable<BtbElseDTO> btbElseDtos)
        {
            BtbElseRepository.ExecuteTransactionNative(()=>
                                                           {
                                                               foreach (var btbElseDto in btbElseDtos)
                                                               {
                                                                   var btb = BtbElseRepository.GetDataOne(x => x.NoBtb == btbElseDto.NoBtb);
                                                                   BtbElseRepository.UpdateStatus(btbElseDto.NoBtb,3);
                                                                   CreateJurnal(btb);
                                                               }
                                                           });
           
        }


        public void UnPosting(IEnumerable<BtbElseDTO> btbElseDtos)
        {
            var jdRepository = new JurnalDetailRepository(session);
            
            BtbElseRepository.ExecuteTransactionNative(() =>
            {
                foreach (var btbElseDto in btbElseDtos)
                {
                    var btb = BtbElseRepository.GetDataOne(x => x.NoBtb == btbElseDto.NoBtb);
                    BtbElseRepository.UpdateStatus(btbElseDto.NoBtb, 0);
                    var jurnal = _jurnalRepository.GetDataOne(x => x.NoVoucher == btb.NoBtb);
                    _jurnalRepository.Delete(jurnal);
                    _hppRepository.DeleteHpp(btbElseDto.NoBtb);
                }
            });
        }
        #endregion
    }
}